package com.youlu.campus.wechat.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.VO.req.QQWxRefundRequest;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.domain.RefundOrderResult;
import com.youlu.campus.service.utils.CommonUtils;
import com.youlu.campus.service.utils.ParseXMLUtils;
import com.youlu.campus.service.utils.PayUtil;
import com.youlu.campus.wechat.enums.WechatPayRefundApiEnum;
import com.youlu.campus.wechat.service.WeChatPayRefundService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 平台认证 微信支付退款服务
 *
 * @Description: WeChatPayRefundServiceImpl
 * @Date 2025/10/20
 * @module WeChatPayRefundServiceImpl
 * @author: su
 */
@Slf4j
public class PlatformWeChatPayRefundServiceImpl implements WeChatPayRefundService {

    /**
     * mongodb 数据库配置验证 md5  避免重复创建
     */
    private final String configMD5;

    private final WechatMerchantConfig wechatMerchantConfig;

    public PlatformWeChatPayRefundServiceImpl(String configMD5, WechatMerchantConfig wechatMerchantConfig) {
        this.wechatMerchantConfig = wechatMerchantConfig;
        this.configMD5 = configMD5;
    }

    @Override
    public String getConfigMD5() {
        return this.configMD5;
    }

    @Override
    public RefundOrderResult applyRefund(QQWxRefundRequest request) {
        //微信退款连接
        String refundUrl = WechatPayRefundApiEnum.PAY_REFUND_V2.getUrl();//申请退款url
        String merchantId = wechatMerchantConfig.getMerchantId();//商户id
        String cc = wechatMerchantConfig.getCc();//证书路径
        log.info("applyRefund merchantId:{},cc:{},request:{}", merchantId, cc, request);
        Map<String, Object> param = new HashMap<>();
        String xmlRequest = buildRefundParamXml(request, param);
        log.info("applyRefund 生成的xml:{}", xmlRequest);
        String nullKeys = param.keySet().stream().filter(k -> param.get(k) == null).collect(Collectors.joining(","));
        if (!nullKeys.isEmpty()) {
            log.error("applyRefund 请求参数为空");
            throw new BusinessException("申请退款请求参数中有为空");
        }
        RestTemplate sslRestTemplate = CommonUtils.getSSLRestTemplate(cc, merchantId);
        ResponseEntity<String> response = sslRestTemplate.postForEntity(refundUrl, xmlRequest, String.class);
        log.info("applyRefund 请求返回值 response:{}", JSONObject.toJSONString(response));
        String body = response.getBody();
        RefundOrderResult result = null;
        try {
            result = ParseXMLUtils.beginXMLParse(body, RefundOrderResult.class);
        } catch (Exception e) {
            throw new BusinessException("申请退款结果集转换异常");
        }
        if (result == null) {
            log.error(":>>> 发起退款失败");
            throw new BusinessException("发起退款失败");
        }
        log.info("applyRefund 退款请求结果:{}", JSON.toJSONString(result));
        return result;
    }

    private String buildRefundParamXml(QQWxRefundRequest request, Map<String, Object> param) {
        StringBuffer bf = new StringBuffer();
        String nonceStr = "" + System.currentTimeMillis();

        bf.append("<xml>");
        if ("qq".equals(request.getPlatform())) {
            bf = appendElement(bf, "appid", request.getWechatAppId(), param);
        } else {
            bf = appendElement(bf, "appid", request.getAppId(), param);
        }
        bf = appendElement(bf, "mch_id", wechatMerchantConfig.getMerchantId(), param);

        bf = appendElement(bf, "nonce_str", nonceStr, param);

        bf = appendElement(bf, "out_trade_no", request.getOrderNo(), param);

        bf = appendElement(bf, "out_refund_no", request.getRefundNo(), param);

        bf = appendElement(bf, "refund_fee", request.getRefundFee(), param);

        bf = appendElement(bf, "total_fee", request.getTotalFee(), param);

        bf = appendElement(bf, "refund_desc", request.getDesc(), param);

        String prestr = PayUtil.createLink(param);

        //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
        String sign = PayUtil.sign(prestr, wechatMerchantConfig.getDesc(), "utf-8").toUpperCase();
        log.info(":>>> 生成的签名:{}", sign);
        bf = appendElement(bf, "sign", sign, param);

        bf.append("</xml>");

        return bf.toString();
    }

    private StringBuffer appendElement(StringBuffer bf, String elementKey, Object elementValue,
                                       Map<String, Object> param) {
        bf.append("<" + elementKey + "><![CDATA[");
        bf.append(elementValue);
        bf.append("]]></" + elementKey + ">");
        if (param != null) {
            param.put(elementKey, elementValue);
        }
        return bf;
    }
}
